package xyz.penghaonan.p2plib.job.base;

import android.os.Handler;
import android.os.HandlerThread;

import com.penghaonan.appframework.utils.WeakObservableList;

import xyz.penghaonan.p2plib.job.JobUtils;

public class BaseJob implements Job {
    private Operation headerOperation;
    private HandlerThread jobThread;
    private Handler jobHandler;
    protected final WeakObservableList<JobListener> jobListenerList = new WeakObservableList<>();
    private final OperationListener innerListener = new OperationListener() {
        @Override
        public void onOperationStart(final Operation operation) {
            operationLog(operation, "<onOperationStart>");
            JobUtils.postOnUIThread(new Runnable() {
                @Override
                public void run() {
                    jobListenerList.iterate(new WeakObservableList.OnIterator<JobListener>() {
                        @Override
                        protected boolean onIterator(JobListener item) {
                            item.onOperationStart(operation);
                            return false;
                        }
                    });
                }
            });
        }

        @Override
        public void onOperationProgress(final Operation operation, final float progress, final String msg) {
            operationLog(operation, "<onOperationProgress> progress:" + progress);
            JobUtils.postOnUIThread(new Runnable() {
                @Override
                public void run() {
                    jobListenerList.iterate(new WeakObservableList.OnIterator<JobListener>() {
                        @Override
                        protected boolean onIterator(JobListener item) {
                            item.onOperationProgress(operation, progress, msg);
                            item.onJobProgress(0f, operation.getName() + " > " + msg);
                            return false;
                        }
                    });
                }
            });
        }

        @Override
        public void onOperationFinish(final Operation operation, final Operation.Result result) {
            operationLog(operation, "<onOperationFinish> result:" + result);
            JobUtils.postOnUIThread(new Runnable() {
                @Override
                public void run() {
                    jobListenerList.iterate(new WeakObservableList.OnIterator<JobListener>() {
                        @Override
                        protected boolean onIterator(JobListener item) {
                            item.onOperationFinish(operation, result);
                            return false;
                        }
                    });
                }
            });
        }
    };

    public BaseJob() {
    }

    public void setHeaderOperation(final Operation headerOperation) {
        this.headerOperation = headerOperation;
    }

    @Override
    public void addListener(JobListener listener) {
        jobListenerList.addListener(listener);
    }

    @Override
    public void removeListener(JobListener listener) {
        jobListenerList.removeListener(listener);
    }

    @Override
    public void start() {
        if (!isStarted()) {
            jobThread = new HandlerThread("Job:" + toString());
            jobThread.start();
            jobHandler = new Handler(jobThread.getLooper());
            log("<onJobStart>");
            JobUtils.postOnUIThread(new Runnable() {
                @Override
                public void run() {
                    jobListenerList.iterate(new WeakObservableList.OnIterator<JobListener>() {
                        @Override
                        protected boolean onIterator(JobListener item) {
                            item.onJobStart();
                            return false;
                        }
                    });
                }
            });
            executeOperation(headerOperation);
        }
    }

    @Override
    public boolean isStarted() {
        return jobThread != null;
    }

    public void executeOperation(final Operation operation) {
        operation.addListener(innerListener);
        jobHandler.post(new Runnable() {
            @Override
            public void run() {
                if (operation != null) {
                    operation.run(BaseJob.this);
                }
            }
        });
    }

    public void notifyJobFinish(final boolean success, final String msg) {
        log("<onJobFinish> success:" + success + ", msg" + msg);
        JobUtils.postOnUIThread(new Runnable() {
            @Override
            public void run() {
                jobListenerList.iterate(new WeakObservableList.OnIterator<JobListener>() {
                    @Override
                    protected boolean onIterator(JobListener item) {
                        item.onJobFinish(success, msg);
                        return false;
                    }
                });
            }
        });
    }

    private void log(String log) {
        JobUtils.log("thread:" + Thread.currentThread().getName() + " job:" + getClass().getSimpleName() + " " + log);
    }

    private void operationLog(Operation operation, String log) {
        log("operation:" + operation.getClass().getSimpleName() + ", " + log);
    }
}
